home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src.arc / TCPSUBR.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  9KB  |  403 lines

  1. #include <stdio.h>
  2. #include "global.h"
  3. #include "timer.h"
  4. #include "mbuf.h"
  5. #include "netuser.h"
  6. #include "internet.h"
  7. #include "tcp.h"
  8. #include "ip.h"
  9.  
  10. static int16 hash_tcb __ARGS((struct connection *conn));
  11.  
  12. /* TCP connection states */
  13. char *Tcpstates[] = {
  14.     "Closed",
  15.     "Listen",
  16.     "SYN sent",
  17.     "SYN received",
  18.     "Established",
  19.     "FIN wait 1",
  20.     "FIN wait 2",
  21.     "Close wait",
  22.     "Closing",
  23.     "Last ACK",
  24.     "Time wait"
  25. };
  26.  
  27. /* TCP closing reasons */
  28. char *Tcpreasons[] = {
  29.     "Normal",
  30.     "Reset/Refused",
  31.     "Timeout",
  32.     "ICMP"
  33. };
  34. struct tcb *Tcbs[NTCB];
  35. int16 Tcp_mss = DEF_MSS;    /* Maximum segment size to be sent with SYN */
  36. int32 Tcp_irtt = DEF_RTT;    /* Initial guess at round trip time */
  37. int Tcp_trace;            /* State change tracing flag */
  38. struct tcp_rtt Tcp_rtt[RTTCACHE];
  39.  
  40. /* Lookup connection, return TCB pointer or NULLTCB if nonexistant */
  41. struct tcb *
  42. lookup_tcb(conn)
  43. struct connection *conn;
  44. {
  45.     register struct tcb *tcb;
  46.  
  47.     tcb = Tcbs[hash_tcb(conn)];
  48.     while(tcb != NULLTCB){
  49.         /* Yet another structure compatibility hack */
  50.         if(conn->local.address == tcb->conn.local.address
  51.          && conn->remote.address == tcb->conn.remote.address
  52.          && conn->local.port == tcb->conn.local.port
  53.          && conn->remote.port == tcb->conn.remote.port)
  54.             break;
  55.         tcb = tcb->next;
  56.     }
  57.     return tcb;
  58. }
  59.  
  60. /* Create a TCB, return pointer. Return pointer if TCB already exists. */
  61. struct tcb *
  62. create_tcb(conn)
  63. struct connection *conn;
  64. {
  65.     register struct tcb *tcb;
  66.     struct tcp_rtt *tp;
  67.  
  68.     if((tcb = lookup_tcb(conn)) != NULLTCB)
  69.         return tcb;
  70.     if((tcb = (struct tcb *)calloc(1,sizeof (struct tcb))) == NULLTCB)
  71.         return NULLTCB;
  72.     ASSIGN(tcb->conn,*conn);
  73.  
  74.     tcb->cwind = tcb->mss = Tcp_mss;
  75.     tcb->ssthresh = 65535;
  76.     if((tp = rtt_get(tcb->conn.remote.address)) != NULLRTT){
  77.         tcb->srtt = tp->srtt;
  78.         tcb->mdev = tp->mdev;
  79.     } else {
  80.         tcb->srtt = Tcp_irtt;    /* mdev = 0 */
  81.     }
  82.     /* Initialize timer intervals */
  83.     tcb->timer.start = tcb->srtt / MSPTICK;
  84.     tcb->timer.func = tcp_timeout;
  85.     tcb->timer.arg = tcb;
  86.  
  87.     link_tcb(tcb);
  88.     return tcb;
  89. }
  90.  
  91. /* Close our TCB */
  92. void
  93. close_self(tcb,reason)
  94. register struct tcb *tcb;
  95. int reason;
  96. {
  97.     struct reseq *rp1;
  98.     register struct reseq *rp;
  99.  
  100.     if(tcb == NULLTCB)
  101.         return;
  102.  
  103.     stop_timer(&tcb->timer);
  104.     tcb->reason = reason;
  105.  
  106.     /* Flush reassembly queue; nothing more can arrive */
  107.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  108.         rp1 = rp->next;
  109.         free_p(rp->bp);
  110.         free((char *)rp);
  111.     }
  112.     tcb->reseq = NULLRESEQ;
  113.     setstate(tcb,CLOSED);
  114. }
  115.  
  116. /* Sequence number comparisons
  117.  * Return true if x is between low and high inclusive,
  118.  * false otherwise
  119.  */
  120. int
  121. seq_within(x,low,high)
  122. register int32 x,low,high;
  123. {
  124.     if(low <= high){
  125.         if(low <= x && x <= high)
  126.             return 1;
  127.     } else {
  128.         if(low >= x && x >= high)
  129.             return 1;
  130.     }
  131.     return 0;
  132. }
  133. int
  134. seq_lt(x,y)
  135. register int32 x,y;
  136. {
  137.     return (long)(x-y) < 0;
  138. }
  139. #ifdef    notdef
  140. int
  141. seq_le(x,y)
  142. register int32 x,y;
  143. {
  144.     return (long)(x-y) <= 0;
  145. }
  146. #endif    /* notdef */
  147. int
  148. seq_gt(x,y)
  149. register int32 x,y;
  150. {
  151.     return (long)(x-y) > 0;
  152. }
  153. int
  154. seq_ge(x,y)
  155. register int32 x,y;
  156. {
  157.     return (long)(x-y) >= 0;
  158. }
  159.  
  160. /* Hash a connect structure into the hash chain header array */
  161. static int16
  162. hash_tcb(conn)
  163. struct connection *conn;
  164. {
  165.     register unsigned int hval;
  166.  
  167.     /* Compute hash function on connection structure */
  168.     hval = hiword(conn->remote.address);
  169.     hval ^= loword(conn->remote.address);
  170. #ifdef    notdef    /* Never changes, so not really needed */
  171.     hval ^= hiword(conn->local.address);
  172.     hval ^= loword(conn->local.address);
  173. #endif
  174.     hval ^= conn->remote.port;
  175.     hval ^= conn->local.port;
  176.     return hval % NTCB;
  177. }
  178. /* Insert TCB at head of proper hash chain */
  179. void
  180. link_tcb(tcb)
  181. register struct tcb *tcb;
  182. {
  183.     register struct tcb **tcbhead;
  184.     char i_state;
  185.  
  186.     tcb->prev = NULLTCB;
  187.     i_state = dirps();
  188.     tcbhead = &Tcbs[hash_tcb(&tcb->conn)];
  189.     tcb->next = *tcbhead;
  190.     if(tcb->next != NULLTCB)
  191.         tcb->next->prev = tcb;
  192.  
  193.     *tcbhead = tcb;
  194.     restore(i_state);
  195. }
  196. /* Remove TCB from whatever hash chain it may be on */
  197. void
  198. unlink_tcb(tcb)
  199. register struct tcb *tcb;
  200. {
  201.     register struct tcb **tcbhead;
  202.     char i_state;
  203.  
  204.     i_state = dirps();
  205.     tcbhead = &Tcbs[hash_tcb(&tcb->conn)];
  206.     if(tcb->prev == NULLTCB)
  207.         *tcbhead = tcb->next;    /* We're the first one on the chain */
  208.     else
  209.         tcb->prev->next = tcb->next;
  210.     if(tcb->next != NULLTCB)
  211.         tcb->next->prev = tcb->prev;
  212.     restore(i_state);
  213. }
  214. void
  215. setstate(tcb,newstate)
  216. register struct tcb *tcb;
  217. register int newstate;
  218. {
  219.     register char oldstate;
  220.  
  221.     oldstate = tcb->state;
  222.     tcb->state = newstate;
  223.     if(Tcp_trace)
  224.         printf("TCB %lx %s -> %s\n",ptol(tcb),
  225.          Tcpstates[oldstate],Tcpstates[newstate]);
  226.     if(tcb->s_upcall)
  227.         (*tcb->s_upcall)(tcb,oldstate,newstate);
  228.  
  229.     switch(newstate){
  230.     case ESTABLISHED:
  231.         /* Notify the user that he can begin sending data */
  232.         if(tcb->t_upcall)
  233.             (*tcb->t_upcall)(tcb,tcb->window - tcb->sndcnt);
  234.         break;
  235.     }
  236. }
  237. /* Convert TCP header in host format into mbuf ready for transmission,
  238.  * link in data (if any), and compute checksum
  239.  */
  240. struct mbuf *
  241. htontcp(tcph,data,ph)
  242. register struct tcp *tcph;
  243. struct mbuf *data;
  244. struct pseudo_header *ph;
  245. {
  246.     int16 hdrlen;
  247.     struct mbuf *bp;
  248.     register char *cp;
  249.     int16 csum;
  250.  
  251.     hdrlen = (tcph->mss != 0) ? TCPLEN + MSS_LENGTH : TCPLEN;
  252.     
  253.     if((bp = pushdown(data,hdrlen)) == NULLBUF){
  254.         free_p(data);
  255.         return NULLBUF;
  256.     }
  257.     cp = bp->data;
  258.     cp = put16(cp,tcph->source);
  259.     cp = put16(cp,tcph->dest);
  260.     cp = put32(cp,tcph->seq);
  261.     cp = put32(cp,tcph->ack);
  262.     *cp++ = hdrlen << 2;    /* Offset field */
  263.     *cp = 0;
  264.     if(tcph->flags.urg)
  265.         *cp |= 32;
  266.     if(tcph->flags.ack)
  267.         *cp |= 16;
  268.     if(tcph->flags.psh)
  269.         *cp |= 8;
  270.     if(tcph->flags.rst)
  271.         *cp |= 4;
  272.     if(tcph->flags.syn)
  273.         *cp |= 2;
  274.     if(tcph->flags.fin)
  275.         *cp |= 1;
  276.     cp++;
  277.     cp = put16(cp,tcph->wnd);
  278.     *cp++ = 0;    /* Zero out checksum field */
  279.     *cp++ = 0;
  280.     cp = put16(cp,tcph->up);
  281.  
  282.     if(tcph->mss != 0){
  283.         *cp++ = MSS_KIND;
  284.         *cp++ = MSS_LENGTH;
  285.         cp = put16(cp,tcph->mss);
  286.     }
  287.     csum = cksum(ph,bp,ph->length);
  288.     /* Fill checksum field */    
  289.     put16(&bp->data[16],csum);
  290.  
  291.     return bp;
  292. }
  293. /* Pull TCP header off mbuf */
  294. int
  295. ntohtcp(tcph,bpp)
  296. register struct tcp *tcph;
  297. struct mbuf **bpp;
  298. {
  299.     int16 hdrlen;
  300.     int16 i,optlen;
  301.     register int flags;
  302.     char hdrbuf[TCPLEN];
  303.  
  304.     i = pullup(bpp,hdrbuf,TCPLEN);
  305.     /* Note that the results will be garbage if the header is too short.
  306.      * We don't check for this because returned ICMP messages will be
  307.      * truncated, and we at least want to get the port numbers.
  308.      */
  309.     tcph->source = get16(&hdrbuf[0]);
  310.     tcph->dest = get16(&hdrbuf[2]);
  311.     tcph->seq = get32(&hdrbuf[4]);
  312.     tcph->ack = get32(&hdrbuf[8]);
  313.     hdrlen = (hdrbuf[12] & 0xf0) >> 2;
  314.     flags = hdrbuf[13];
  315.     tcph->flags.urg = flags & 32;
  316.     tcph->flags.ack = flags & 16;
  317.     tcph->flags.psh = flags & 8;
  318.     tcph->flags.rst = flags & 4;
  319.     tcph->flags.syn = flags & 2;
  320.     tcph->flags.fin = flags & 1;
  321.     tcph->wnd = get16(&hdrbuf[14]);
  322.     tcph->up = get16(&hdrbuf[18]);
  323.     tcph->mss = 0;
  324.  
  325.     /* Check for option field. Only space for one is allowed, but
  326.      * since there's only one TCP option (MSS) this isn't a problem
  327.      */
  328.     if(i < TCPLEN || hdrlen < TCPLEN)
  329.         return -1;    /* Header smaller than legal minimum */
  330.     if(hdrlen == TCPLEN)
  331.         return hdrlen;    /* No options, all done */
  332.  
  333.     if(hdrlen > len_mbuf(*bpp) + TCPLEN){
  334.         /* Remainder too short for options length specified */
  335.         return -1;
  336.     }
  337.     /* Process options */
  338.     for(i=TCPLEN; i < hdrlen;){
  339.         switch(pullchar(bpp)){
  340.         case EOL_KIND:
  341.             i++;
  342.             goto eol;    /* End of options list */
  343.         case NOOP_KIND:
  344.             i++;
  345.             break;
  346.         case MSS_KIND:
  347.             optlen = pullchar(bpp);
  348.             if(optlen == MSS_LENGTH)
  349.                 tcph->mss = pull16(bpp);
  350.             i += optlen;
  351.             break;
  352.         }
  353.     }
  354. eol:
  355.     /* Get rid of any padding */
  356.     if(i < hdrlen)
  357.         pullup(bpp,NULLCHAR,hdrlen - i);
  358.     return hdrlen;
  359. }
  360. /* Round trip timing cache routines.
  361.  * These functions implement a very simple system for keeping track of
  362.  * network performance for future use in new connections.
  363.  * The emphasis here is on speed of update (rather than optimum cache hit
  364.  * ratio) since rtt_add is called every time a TCP connection updates
  365.  * its round trip estimate.
  366.  */
  367. void
  368. rtt_add(addr,rtt)
  369. int32 addr;        /* Destination IP address */
  370. int32 rtt;
  371. {
  372.     register struct tcp_rtt *tp;
  373.     int32 abserr;
  374.  
  375.     if(addr == 0)
  376.         return;
  377.     tp = &Tcp_rtt[(unsigned short)addr % RTTCACHE];
  378.     if(tp->addr != addr){
  379.         /* New entry */
  380.         tp->addr = addr;
  381.         tp->srtt = rtt;
  382.         tp->mdev = 0;
  383.     } else {
  384.         /* Run our own SRTT and MDEV integrators, with rounding */
  385.         abserr = (rtt > tp->srtt) ? rtt - tp->srtt : tp->srtt - rtt;
  386.         tp->srtt = ((AGAIN-1)*tp->srtt + rtt + (AGAIN/2)) >> LAGAIN;
  387.         tp->mdev = ((DGAIN-1)*tp->mdev + abserr + (DGAIN/2)) >> LDGAIN;
  388.     }
  389. }
  390. struct tcp_rtt *
  391. rtt_get(addr)
  392. int32 addr;
  393. {
  394.     register struct tcp_rtt *tp;
  395.  
  396.     if(addr == 0)
  397.         return NULLRTT;
  398.     tp = &Tcp_rtt[(unsigned short)addr % RTTCACHE];
  399.     if(tp->addr != addr)
  400.         return NULLRTT;
  401.     return tp;
  402. }
  403.